/*
*	Author: Nikhil
*	Date: Feb 28, 2012
*	This file will have code for data hazards..
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct commonDataBus
{
	char reg[10];
	unsigned long long inscounter;
	struct commonDataBus *next;
}*list, *firstlist;
typedef struct commonDataBus cdb;

void init(void)
{
	list = NULL;
	firstlist = NULL;
}

// I should check and insert here.. if it is already existing, then do what?
int cdb_entry(cdb cdbentry)
{
	struct commonDataBus *p;
	p = (struct commonDataBus*) malloc(sizeof(struct commonDataBus));
	strcpy(p->reg, cdbentry.reg);
	p->next = NULL;

	list = firstlist;
	if( list == NULL )
	{
		list = p;
		firstlist = list;
	}
	else
	{
		while(list->next != NULL)
			list = list->next;
	 	list->next = p;
	}
	return 0;
}

//Returns 0 for not found.. 1 for found..
int cdb_checkentry(char regtr[])
{
	list = firstlist;
	if( list == NULL )
		return 0;
	else
	{
		while(list != NULL)
		{
			if(strcmp(list->reg, regtr) == 0)
				return 1;
			list = list->next;
		}
	}
	return 0;
}

int cdb_removeentry(char regtr[], unsigned long long counter)
{
	cdb *temp = (struct commonDataBus*) malloc(sizeof(struct commonDataBus));
	list = firstlist;
	if( list == NULL )
	{
		printf("Error condition\n");
		return -1;
	}
	else
	{
		while(list != NULL)
		{
			if( (strcmp(regtr,list->reg) == 0) && (counter == list->inscounter) )
			{
				printf("Match.. I should remove this\n");
				temp = list->next;
				free(list);
				list = temp;
				break;
			}
			list = list->next;
		}
	}
	return 0;
}

struct regFile
{
	char reg[5];
	int busy; // 0 - free, 1 - busy
	unsigned long long inscounter;
	struct regFile *next;
}*rfile, *firstrfile;
typedef struct regFile regfile;

void initregfile(void)
{
	rfile = NULL;
	firstrfile = NULL;
}

void copytop(regfile *p, regfile *regentry)
{
	p->busy = regentry->busy;
	p->inscounter = regentry->inscounter;
	strcpy(p->reg, regentry->reg);
}

regfile * reg_search(char []);

// I should check and insert here.. if it is already existing, then do what?
int regfile_insert(char reg[], unsigned long long ins_counter)
{
        struct regFile *p;
	if( (p=reg_search(reg)) == NULL)
	{
		//printf("Insert reg %s, count %lld\n",reg,ins_counter);
        	p = (struct regFile*) malloc(sizeof(struct regFile));
		strcpy(p->reg, reg);
		p->inscounter = ins_counter;
		p->busy = 1;
        	p->next = NULL;
        	rfile = firstrfile;
        	if( rfile == NULL )
        	{
                	rfile = p;
                	firstrfile = rfile;
        	}
        	else
        	{
                	while(rfile->next != NULL)
                        	rfile = rfile->next;
                	rfile->next = p;
        	}
	}
        return 0;
}

regfile* reg_search(char reg[])
{
	regfile *regentry = NULL;
	rfile = firstrfile;
	if( rfile == NULL )
	{
		return regentry;
	}
	else
	{
		while(rfile != NULL)
		{
			if( strcmp(rfile->reg,reg) == 0 )
			{
				return rfile;
			}
			rfile = rfile->next;
		}
	}
	return regentry;
}

void disp_reg()
{
	regfile *regentry = NULL;
	rfile = firstrfile;
	if( rfile == NULL )
	{
		printf("Empty Reg list\n");	
	}
	else
	{
		while(rfile != NULL)
		{
			printf("Reg : %s, busy: %d\n", rfile->reg, rfile->busy);
			rfile = rfile->next;
		}
	}
}

void reg_removebusy(char reg[])
{
        struct regFile *p;
	if( (p=reg_search(reg)) == NULL)
		printf("Error condition\n");
	else
		p->busy = 0;
}

//1 - success, 0 - failure
int check_reg(char reg[], unsigned long long counter)
{
        struct regFile *p;
	if( (p=reg_search(reg)) == NULL)
		printf("Error condition\n");
	else
	{
		/*printf("Reg %s\n",p->reg);
		printf("Busy %d\n",p->busy);
		printf("Inscounter %lld\n",p->inscounter);
		printf("counter %lld\n",counter);*/
		if(p->inscounter == counter)
		{
			return 1;
		}
		else if(p->busy == 0)
		{
			p->inscounter = counter;
			p->busy = 1;
			return 1;
		}
	}
	return 0;
}

int check_regbusy(char reg[])
{
	struct regFile *p;
	if ( (p=reg_search(reg)) == NULL)
		printf("error\n");
	else
	{
		if(p->busy == 0)
			return 0;
		else
			return 1;
	}
}

//Returns 1 - execute, 0 - stall, -1 - error
int ins_executeorstall(ins instr1)
{
	if(instr1.reg1 == 1 || instr1.reg1 == 2)
		if(check_reg(instr1.creg1, instr1.inscounter) != 1) return 0;
	if(instr1.reg2 == 1 || instr1.reg2 == 2)
		if(check_reg(instr1.creg2, instr1.inscounter) != 1) return 0;
	if(instr1.reg3 == 1 || instr1.reg3 == 2)
		if(check_reg(instr1.creg3, instr1.inscounter) != 1) return 0;
	if(instr1.reg4 == 1 || instr1.reg4 == 2)
		if(check_reg(instr1.creg4, instr1.inscounter) != 1) return 0;
	if(instr1.reg5 == 1 || instr1.reg5 == 2)
		if(check_reg(instr1.creg5, instr1.inscounter) != 1) return 0;
	if(instr1.reg6 == 1 || instr1.reg6 == 2)
		if(check_reg(instr1.creg6, instr1.inscounter) != 1) return 0;
	if(instr1.reg7 == 1 || instr1.reg7 == 2)
		if(check_reg(instr1.creg7, instr1.inscounter) != 1) return 0;
	if(instr1.reg8 == 1 || instr1.reg8 == 2)
		if(check_reg(instr1.creg8, instr1.inscounter) != 1) return 0;
	return 1;
}

//For store instruction only
int ins_executeorstall_store(ins instr1)
{
	if(instr1.reg1 == 2)
		if(check_reg(instr1.creg1, instr1.inscounter) != 1) return 0;
	if(instr1.reg2 == 2)
		if(check_reg(instr1.creg2, instr1.inscounter) != 1) return 0;
	if(instr1.reg3 == 2)
		if(check_reg(instr1.creg3, instr1.inscounter) != 1) return 0;
	if(instr1.reg4 == 2)
		if(check_reg(instr1.creg4, instr1.inscounter) != 1) return 0;
	if(instr1.reg5 == 2)
		if(check_reg(instr1.creg5, instr1.inscounter) != 1) return 0;
	if(instr1.reg6 == 2)
		if(check_reg(instr1.creg6, instr1.inscounter) != 1) return 0;
	if(instr1.reg7 == 2)
		if(check_reg(instr1.creg7, instr1.inscounter) != 1) return 0;
	if(instr1.reg8 == 2)
		if(check_reg(instr1.creg8, instr1.inscounter) != 1) return 0;
	return 1;
}

//For load instruction only
int ins_executeorstall_load(ins instr1)
{
	if(instr1.reg1 == 1)
		if(check_reg(instr1.creg1, instr1.inscounter) != 1) return 0;
	if(instr1.reg2 == 1)
		if(check_reg(instr1.creg2, instr1.inscounter) != 1) return 0;
	if(instr1.reg3 == 1)
		if(check_reg(instr1.creg3, instr1.inscounter) != 1) return 0;
	if(instr1.reg4 == 1)
		if(check_reg(instr1.creg4, instr1.inscounter) != 1) return 0;
	if(instr1.reg5 == 1)
		if(check_reg(instr1.creg5, instr1.inscounter) != 1) return 0;
	if(instr1.reg6 == 1)
		if(check_reg(instr1.creg6, instr1.inscounter) != 1) return 0;
	if(instr1.reg7 == 1)
		if(check_reg(instr1.creg7, instr1.inscounter) != 1) return 0;
	if(instr1.reg8 == 1)
		if(check_reg(instr1.creg8, instr1.inscounter) != 1) return 0;
	return 1;
}

void removebusy_readreg(ins instr1)
{
	if(instr1.reg1 == 1)
		reg_removebusy(instr1.creg1);
	if(instr1.reg2 == 1)
		reg_removebusy(instr1.creg2);
	if(instr1.reg3 == 1)
		reg_removebusy(instr1.creg3);
	if(instr1.reg4 == 1)
		reg_removebusy(instr1.creg4);
	if(instr1.reg5 == 1)
		reg_removebusy(instr1.creg5);
	if(instr1.reg6 == 1)
		reg_removebusy(instr1.creg6);
	if(instr1.reg7 == 1)
		reg_removebusy(instr1.creg7);
	if(instr1.reg8 == 1)
		reg_removebusy(instr1.creg8);
}

void removebusy_writereg(ins instr1)
{
	if(instr1.reg1 == 2)
		reg_removebusy(instr1.creg1);
	if(instr1.reg2 == 2)
		reg_removebusy(instr1.creg2);
	if(instr1.reg3 == 2)
		reg_removebusy(instr1.creg3);
	if(instr1.reg4 == 2)
		reg_removebusy(instr1.creg4);
	if(instr1.reg5 == 2)
		reg_removebusy(instr1.creg5);
	if(instr1.reg6 == 2)
		reg_removebusy(instr1.creg6);
	if(instr1.reg7 == 2)
		reg_removebusy(instr1.creg7);
	if(instr1.reg8 == 2)
		reg_removebusy(instr1.creg8);
}
